/*
 *  myqq.c
 *
 *  main() A small console for MyQQ.
 *
 *  Copyright (C) 2008  Huang Guan (gdxxhg@gmail.com)
 *
 *  2008-01-31 Created.
 *  2008-2-5   Add more commands.
 *  2008-7-15  Mr. Wugui said "There's no accident in the world.",
 *		   but I always see accident in my code :)
 *  2008-10-1  Character color support and nonecho password.
 *  2009-1-25  Use UTF-8 as a default type.
 *
 *  Description: This file mainly includes the functions about
 *			   Parsing Input Commands.
 *		 Warning: this file should be in UTF-8.
 *
 */

//#include "debug.h"
#include "directory.h"
#include "console.h"
#include "utf8.h"
#include "qqclient.h"
#include "buddy.h"
#include "qun.h"
#include "group.h"
#include "memory.h"
#include "config.h"
#include "qqsocket.h"

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#ifdef __WIN32__
#include <winsock.h>
#include <wininet.h>
#include <windows.h>
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif

#define QUN_BUF_SIZE	80*100
#define BUDDY_BUF_SIZE	80*500
#define PRINT_BUF_SIZE	80*500*3

lua_State* L;
lua_State* tL;


static char *qun_buf, *buddy_buf, *print_buf;
static uint to_uid = 0;		//send message to that guy.
static uint qun_int_uid;		//internal qun id if entered.
static char input[1024];
static int enter = 0;
static qqclient* qq;
static uint auto_login=0;
static uint uid;
static char password[256];


int load_last_cmd();
void save_last_cmd(char cmd[],char arg[]);
static int messageLoop();

enum
{
	CMD_DBG = 0,
	CMD_EXIT,
	CMD_SAY,
	CMD_PIC,
	CMD_TO,
	CMD_HELP,
	CMD_STATUS,
	CMD_ENTER,
	CMD_LEAVE,
	CMD_WHO,
	CMD_VIEW,
	CMD_QUN,
	CMD_INFO,
	CMD_UPDATE,
	CMD_CHANGE,
	CMD_TEST,
	CMD_VERIFY,
	CMD_ADD,
	CMD_DEL,
	CMD_CLS,
	CMD_RRLOAD,
	CMD_SET_FONT_NAME,
	CMD_SET_FONT_SIZE,
};
static char commands[][20]=
{
	"debug",
	"exit",
	"say",
	"pic",
	"to",
	"help",
	"status",
	"enter",
	"leave",
	"who",
	"view",
	"qun",
	"info",
	"update",
	"change",
	"test",
	"verify",
	"add",
	"del",
	"cls",
	"reload",
	"fontname",
	"fontsize",
	"show"
};

static char help_msg[]=
	"欢迎使用 MyQQ2009 中文版\n"
	"这是一个为程序员和电脑爱好者制作的"
	"迷你控制台即时通讯软件,享受它吧!\n"
	"help:		显示以下帮助信息.\n"
	"add:		添加好友. add+QQ号码.\n"
	"view:		所有好(群)友列表.(指向前操作)\n"
	"who:		在线好(群)友列表.(指向前操作)\n"
	"qun:		显示群列表.(指向前操作)\n"
	"to:		指向某个QQ号或者前面的编号.\n"
	"enter:		指向某个群号或者前面的编号.\n"
	"leave:		离开群.(指向后操作)\n"
	"say:		发送信息.(指向后操作)\n"
	"pic:		发送图片.(指向后操作) * 不可用\n"
	"info:		查看相应信息.(指向后操作)\n"
	"update:		更新所有列表.\n"
	"status:		改变状态(online|away|busy|killme|hidden)\n"
	"fontname:	改变QQ字体.\n"
	"fontsize:	改变QQ字号.\n"
	"cls:		清屏.\n"
	"verify:		输入验证码(验证码在verify目录下).\n"
	"change:		重新登陆.\n"
	"reload:		重新读取lua代码.\n"
	"debug:		调试信息开关[+|-][f|t|r|s](文件|屏幕|接收|发送).\n"
	"exit:		退出.\n"
	;

#ifdef __WIN32__
#define _TEXT to_gb_force
static char* to_gb_force( char* s )
{
//	memset( print_buf, 0, PRINT_BUF_SIZE );
	utf8_to_gb( s, print_buf, PRINT_BUF_SIZE-1 );
	return print_buf;
}
static char* to_utf8( char* s )
{
//	memset( print_buf, 0, PRINT_BUF_SIZE );
	gb_to_utf8( s, print_buf, PRINT_BUF_SIZE-1 );
	return print_buf;
}
#else
#define _TEXT
#endif


int lua_pcall_to_dir(lua_State *L, int nargs, int nresults, int errfunc){
	remberdir();
	mchdata();
	static int ret = 0;
	ret = lua_pcall(L,nargs,nresults,errfunc);
	resumedir();
	return ret;
}

static int getline(char *s, int lim)
{

	char *t;
	int c;

	t = s;
	while (--lim>1 && (c=getchar()) != EOF && c != '\n')
		*s++ = c;
	*s = '\0';
	return s - t;
}

static char* mode_string( int mode )
{

	switch( mode )
	{
	case QQ_ONLINE:
		return "Online";
	case QQ_AWAY:
		return "Away";
	case QQ_BUSY:
		return "Busy";
	case QQ_OFFLINE:
		return "Offline";
	case QQ_HIDDEN:
		return "Hidden";
	case QQ_KILLME:
		return "Kill Me";
	case QQ_QUIET:
		return "Quiet";
	}
	return "Unknown";
}
static char* skip_line( char* p, int ln )
{

	while( *p && ln-- )
	{
		p ++;
		while( *p && *p!='\n' ) p++;
	}
	return p;
}
static char* myqq_get_buddy_name( qqclient* qq, uint uid )
{
	if( uid == 10000 )
		return "System";
	static char tmp[16];
	qqbuddy* b = buddy_get( qq, uid, 0 );
	if( b )
		return b->nickname;
	if( uid != 0 )
	{
		sprintf( tmp, "%u" , uid );
		return tmp;
	}
	return "Nobody";
}
static char* myqq_get_qun_name( qqclient* qq, uint uid )
{

	static char tmp[16];
	qqqun* q = qun_get( qq, uid, 1 );
	if( q )
		return q->name;
	if( uid != 0 )
	{
		sprintf( tmp, "%u" , uid );
		return tmp;
	}
	return "[q==NULL]";
}
static char* myqq_get_qun_member_name( qqclient* qq, uint int_uid, uint uid )
{

	static char tmp[16];
	qqqun* q = qun_get( qq, int_uid, 0 );
	if( q )
	{
		qunmember* m = qun_member_get( qq, q, uid, 0 );
		if( m )
			return m->nickname;
		if( uid != 0 )
		{
			sprintf( tmp, "%u" , uid );
			return tmp;
		}
		return "[m==NULL]";
	}
	return "[q==NULL]";
}
static int myqq_send_im_to_qun( qqclient* qq, uint int_uid, char* msg, int wait )
{

	qun_send_message( qq, int_uid, msg );
	if( wait )
	{
		if( qqclient_wait( qq, 15 ) < 0 )
			return -1;
	}
	//RESET_INPUT
	return 0;
}

static int myqq_send_picim_to_qun( qqclient* qq, uint int_uid, char* pic, int wait )
{

	prot_qun_send_img( qq, int_uid, pic );
	if( wait )
	{
		if( qqclient_wait( qq, 15 ) < 0 )
			return -1;
	}
	//RESET_INPUT
	return 0;
}

static int myqq_send_im_to_buddy( qqclient* qq, uint int_uid, char* msg, int wait )
{

	buddy_send_message( qq, int_uid, msg );
	if( wait )
	{
		if( qqclient_wait( qq, 15 ) < 0 )
			return -1;
	}
	return 0;
}

static int myqq_get_buddy_info( qqclient* qq, uint uid, char* buf, int size )
{

	qqbuddy *b = buddy_get( qq, uid, 0 );
	if( size < 256 )
		return -1;
	if( b == NULL )
		return -2;
	int len;
	len = sprintf( buf,	"好友昵称\t%s\n"
				   "用户账号\t%d\n"
				   "签名\t\t%s\n"
				   "备注\t\t%s\n"
				   "手机\t\t%s\n"
				   "邮箱\t\t%s\n"
				   "职业\t\t%s\n"
				   "主页\t\t%s\n"
				   "毕业学院\t%s\n"
				   "来自\t\t%s %s %s\n"
				   "通讯地址\t%s\n"
				   "自我介绍\t%s\n"
				   "头像\t\t%d\n"
				   "年龄\t\t%d\n"
				   "性别\t\t%s\n"
				   "状态\t\t%s\n",
				   b->nickname, b->number, b->signature, b->alias, b->mobilephone,
				   b->email, b->occupation, b->homepage, b->school, b->country, b->province, b->city,
				   b->address, b->brief, b->face, b->age,
				   (b->sex==0x00)?"Male": (b->sex==0x01)?"Female":"Asexual", mode_string(b->status) );
	return len;
}


//Note: this function change the source string directly.
static char* util_escape( char* str )
{

	unsigned char* ch;
	ch = (unsigned char*)str;
	while( *ch )
	{
		if( *ch < 0x80 ) //ASCII??
		{
			if( !isprint(*ch) ) //if not printable??
				*ch = ' ';	//use space instead..
			ch ++;	//skip one
		}
		else
		{
			ch +=2; //skip two
		}
	}
	return str;
}

/*   The output buf looks like this:
L8bit  L16bit		L16bit		L32bit
1	  357339036	 online		Xiao xia
2	  273310179	 offline	Huang Guan
*/
//Note: size must be big enough
static int myqq_get_buddy_list( qqclient* qq, char* buf, int size, char online )
{

	int i, len = 0;
	//avoid editing the array
	buf[0] = 0;
	pthread_mutex_lock( &qq->buddy_list.mutex );
	int ln = 1;
	for( i=0; i<qq->buddy_list.count; i++ )
	{
		qqbuddy * b = (qqbuddy*)qq->buddy_list.items[i];
		if( online && b->status == QQ_OFFLINE ) continue;
		if( *b->alias )
		{
			len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln ++, b->number,
						   mode_string( (int) b->status ), util_escape( b->alias ) );
		}
		else
		{
			len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln ++, b->number,
						   mode_string( (int) b->status ), util_escape( b->nickname ) );
		}
		if( len + 80 > size ) break;
	}
	pthread_mutex_unlock( &qq->buddy_list.mutex );
	return len;
}

/*   The output buf looks like this:
L8bit  L16bit		L16bit		L32bit
1	  467788923	 12118724	Xinxing Experimental School
2	  489234223	 13223423	SGOS2007
*/
//Note: size must be big enough
static int myqq_get_qun_list( qqclient* qq, char* buf, int size )
{

	int i, len = 0, ln=1;
	//avoid editing the array
	buf[0] = 0;
	pthread_mutex_lock( &qq->qun_list.mutex );
	for( i=0; i<qq->qun_list.count; i++ )
	{
		qqqun * q = (qqqun *)qq->qun_list.items[i];
		len = sprintf( buf, "%s%-8d%-16d%-16d%-16.64s\n", buf, ln ++, q->number,
					   q->ext_number, util_escape( q->name ) );
		if( len + 80 > size ) break;
	}
	pthread_mutex_unlock( &qq->qun_list.mutex );
	return len;
}

/*   The output buf looks like this:
L8bit  L16bit		L16bit		L32bit
1	  357339036	 Manager	Xiaoxia
2	  273310179	 Fellow		Huang Guan
*/
//Note: size must be big enough
static int myqq_get_qun_member_list( qqclient* qq, uint int_uid, char* buf, int size, char online )
{

	qqqun * q = qun_get( qq, int_uid, 0 );
	if( !q )return 0;
	//Hope the Qun won't get removed while we are using it.
	int i, len = 0, ln = 1;
	buf[0] = 0;
	pthread_mutex_lock( &q->member_list.mutex );
	for( i=0; i<q->member_list.count; i++ )
	{
		qunmember * m = (qunmember *)q->member_list.items[i];
		if( online && m->status == QQ_OFFLINE ) continue;
		len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln++, m->number,
					   (m->role&1)?"Admin":"Fellow", util_escape( m->nickname ) );
		if( len + 80 > size )
			break;
	}
	pthread_mutex_unlock( &q->member_list.mutex );
	return len;
}

//interface for getting qun information
/* Output style:
*/
static int myqq_get_qun_info( qqclient* qq, uint int_uid, char* buf, int size )
{

	char cate_str[4][10] = {"Classmate", "Friend", "Workmate", "Other" };
	qqqun *q = qun_get( qq, int_uid, 0 );
	if( !q )return 0;
	int len;
	if( size < 256 )
		return -1;

	if( q == NULL )
		return -2;
	len = sprintf( buf, 	"名称\t\t%s\n"
				   "内部号码\t%d\n"
				   "群号码\t\t%d\n"
				   "群类型\t\t%s\n"
				   "加入验证\t%s\n"
				   "群分类\t\t%s\n"
				   "创建人\t\t%d\n"
				   "成员数量\t%d\n"
				   "群的简介\n%s\n"
				   "群的公告\n%s\n",
				   q->name, q->number, q->ext_number, (q->type==0x01)?"Normal":"Special",
				   (q->auth_type==0x01)?"No": (q->auth_type==0x02)?"Yes":
				   (q->auth_type==0x03)?"RejectAll":"Unknown",
				   q->category > 3 ? cate_str[3] : cate_str[(int)q->category],
				   q->owner, q->member_list.count, q->intro, q->ann );
	return len;
}

//含颜色控制
void buddy_msg_callback ( qqclient* qq, uint uid, time_t t, char* msg )
{

	charcolor( CCOL_LIGHTBLUE );	//red color
	char timestr[12];
	char msgstr[64];
	struct tm * timeinfo;
	char* nick = myqq_get_buddy_name( qq, uid );
	timeinfo = localtime ( &t );
	strftime( timestr, 12, "%H:%M:%S", timeinfo );
	char tmp[20], *p;
	sprintf( tmp, "%-16d", uid );
	p = strstr( buddy_buf, tmp );
	if( p )
	{
		p -= 8;
		if( p>=buddy_buf )
		{
			int ln;
			sscanf( p, "%d", &ln );
			sprintf( msgstr, "\n%d)%s[", ln, timestr );
			strcat( msgstr, nick );
			strcat( msgstr, "]\n\t" );//二次修改
			MSG( _TEXT( msgstr ) );
			MSG( "%s\n", _TEXT( msg ) );
			//-----------
			lua_getglobal(L, "main_buddy");
			lua_pushstring(L,_TEXT(msg));
			lua_pushstring(L,timestr);
			lua_pushstring(L,_TEXT(nick));
			lua_pushnumber(L,uid);
			if (lua_pcall_to_dir(L, 4, 0, 0) != 0){
				MSG("ERR-----");
				MSG(lua_tostring(L, -1));
				MSG("\n");
			}
			RESET_INPUT
		}
	}
	else
	{
		sprintf( msgstr, "\n%s[", timestr );
		strcat( msgstr, nick );
		strcat( msgstr, "]\n\t" );//二次修改
		MSG( _TEXT( msgstr ) );
		MSG( "%s\n", _TEXT( msg ) );
		//-----------
		lua_getglobal(L, "main_buddy");
		lua_pushstring(L,_TEXT(msg));
		lua_pushstring(L,timestr);
		lua_pushstring(L,_TEXT(nick));
		lua_pushnumber(L,uid);
		if (lua_pcall_to_dir(L, 4, 0, 0) != 0){
			MSG("ERR-----");
			MSG(lua_tostring(L, -1));
			MSG("\n");
		}

		RESET_INPUT
	}
}

//含颜色控制
void qun_msg_callback ( qqclient* qq, uint uid, uint int_uid,
						time_t t, char* msg )
{
	charcolor( CCOL_REDGREEN );	//yellow color
	char timestr[12];
	char msgstr[64];
	char* qun_name = myqq_get_qun_name( qq, int_uid );
	char* nick = myqq_get_qun_member_name( qq, int_uid, uid );
	struct tm * timeinfo;
	timeinfo = localtime ( &t );
	strftime( timestr, 12, "%H:%M:%S", timeinfo );
	char tmp[20], *p;
	sprintf( tmp, "%-16d", int_uid );
	p = strstr( qun_buf, tmp );
	if( p )
	{
		p -= 8;
		if( p>=qun_buf )
		{
			int ln;
			sscanf( p, "%d", &ln );
			sprintf( msgstr, "\n%d)%s{", ln, timestr );
			strcat( msgstr, qun_name );
			strcat( msgstr, "}[" );
			strcat( msgstr, nick );
			strcat( msgstr, "]\n\t" );//二次修改
			MSG( _TEXT( msgstr ) );
			MSG( "%s\n", _TEXT( msg ) );
			//---------------------
			lua_getglobal(L, "main");
			lua_pushstring(L,_TEXT(msg));
			lua_pushstring(L,timestr);
			lua_pushstring(L,_TEXT(nick));
			lua_pushnumber(L,uid);
			lua_pushstring(L,_TEXT(qun_name));
			lua_pushnumber(L,int_uid);
			
			if (lua_pcall_to_dir(L, 6, 0, 0) != 0){
				MSG("ERR-----");
				MSG(lua_tostring(L, -1));
				MSG("\n");
			}
			RESET_INPUT
		}
	}
	else
	{
		sprintf( msgstr, "\n%s{", timestr );
		strcat( msgstr, qun_name );
		strcat( msgstr, "}[" );
		strcat( msgstr, nick );
		strcat( msgstr, "]\n\t" );//二次修改
		MSG( _TEXT( msgstr ) );
		MSG( "%s\n", _TEXT( msg ) );
		//---------------------
		lua_getglobal(L, "main");
		lua_pushstring(L,_TEXT(msg));
		lua_pushstring(L,_TEXT(timestr));
		lua_pushstring(L,_TEXT(nick));
		lua_pushnumber(L,uid);
		lua_pushstring(L,_TEXT(qun_name));
		lua_pushnumber(L,int_uid);
		//PAUSE
		
		if (lua_pcall_to_dir(L, 6, 0, 0) != 0){
			MSG("ERR-----");
			MSG(lua_tostring(L, -1));
			MSG("\n");
		}
		RESET_INPUT
	}
}

static int lua_say_qun(lua_State *L)
{
	const char *msg=luaL_checkstring(L,1);
	uint qun_id=(uint)luaL_checkint(L,2);
	myqq_send_im_to_qun( qq, qun_id, to_utf8((char *)msg), 0 );

	MSG( _TEXT("**lua代码发送群消息**\n"));
	charcolor(CCOL_HIYELLOW);
	MSG("%d >> %.80s\n", qun_id ,_TEXT( to_utf8( (char *)msg)));
	charcolor(CCOL_NONE);
	return 0;
}

static int lua_say_buddy(lua_State *L)
{

	const char *msg=luaL_checkstring(L,1);
	uint qun_id=(uint)luaL_checkint(L,2);
	myqq_send_im_to_buddy( qq, qun_id, to_utf8((char *)msg), 0 );

	MSG( _TEXT("**lua代码发送QQ消息**\n"));
	charcolor(CCOL_HIYELLOW);
	MSG( "%d >> %.80s\n", qun_id , _TEXT( to_utf8( (char *)msg)));
	charcolor(CCOL_NONE);
	return 0;
}

static int lua_to_gb_force(lua_State *L)
{

	const char *input=luaL_checkstring(L,1);
	char * output=to_gb_force((char *)input);
	//jiu1MSG(output);
	lua_pushstring(L,output);
	return 1;
}

static int lua_charcolore(lua_State *L)
{

	fflush( stdout );
	charcolor(luaL_checkint(L,1));
	setcolor( color_index );
	return 1;
}

/*long getfilesize(const char *fname)
{
	int fp;
	fp=_open(fname,_O_RDONLY);
	if(fp==-1) 
		return 0;
	return _lseek(fp,0,SEEK_END);
	//return NULL;
}*/

static int lua_LoadAddin(lua_State *L)
{
	const char *msg=luaL_checkstring(L,1);

	/*mchdir(lua);
	FILE *fin;	char *str;	long int i=0;long fl=0;

	fl=getfilesize(msg)+1;
	str = (char*) malloc(fl);

	fin = fopen( msg , "r" );
	while (!feof(fin)) {
		str[i] = fgetc(fin);
		i++;
	}
	MSG((str));*/

	mchdir(libs);

	/*strcpy( pathcatbuff , normaldir );
	strcat( pathcatbuff , LUAPATH );*/
	ZeroMemory(pathcatbuff,4096);
	strcat( pathcatbuff , "..\\luascript\\" );
	MSG("LOAD_SCRIPT : %s\n",strcat( pathcatbuff , msg ));

	if (luaL_dofile( L , pathcatbuff ) != 0){
		setcolor( CCOL_RED );
		MSG(lua_tostring(L, -1));
		MSG(_TEXT("\n"));
		setcolor( CCOL_NONE );
		return 0;
	}
	
	return 1;
}

static int get_script(lua_State *L)
{

	const char *input=luaL_checkstring(L,1);
	char * output=to_gb_force((char *)input);
	//jiu1MSG(output);
	MSG(_TEXT("\n运行\n"));
	lua_pushstring(L,output);
	return 1;
}

static int lua_loadlib(lua_State *L)
{
	getcwd ( nowdir ,4096 );
	//jiu1MSG(output);
	mchdir(libs);
	return 1;
}

int Build_script_r()
{
	mchdir(root);

	FILE *fp=fopen("settings\\qq.lua","rt");
	if (fp==NULL)goto CREAT_NEW;
	fclose(fp);fp=NULL;

#define ITHAS if(lua_isnoneornil(L,-1)!=0)goto CREAT_NEW;

	L=lua_open();
	luaL_openlibs(L);
	luaL_dofile(L,"settings\\qq.lua");

	lua_getglobal(L,"auto");
	ITHAS
	auto_login = (uint)lua_tonumber(L, -1);
	if (auto_login==0) goto CREAT_NEW;
	MSG("AutoLogin : %s\n", _TEXT(auto_login==0 ? "否" : "是"));

	lua_getglobal(L,"uid");
	ITHAS
	uid = (uint)lua_tonumber(L, -1);
	MSG("UserID : %d\n",uid);

	lua_getglobal(L,"password");
	ITHAS
	strcpy(password,lua_tostring(L,-1));
	MSG("Password : %s\n",password);
	lua_close(L);

	return 1;
CREAT_NEW:
	clear_screen();
	assert(!fp);
	fp=fopen("settings\\qq.lua","wt");
	rebuild_qqRember(fp);
	fclose(fp);
	return 0;
}

int rebuild_qqRember(FILE *fp){
	char num[50];char pass[50];
	printf(_TEXT("请输入QQ号："));
	scanf("%s",num);
	uid=atoi(num);
	printf(_TEXT("请输入密码："));
	scanf("%s",pass);
	strcpy( password , pass );
		
	printf(_TEXT("下次自动登录(自动登录按y，否则任意键继续)："));
	if (getch()=='y')
		auto_login=1;
	else
		auto_login=0;

	fprintf(fp , "auto=%d\n" , auto_login);
	if (auto_login){
		fprintf(fp , "uid=%s\n" , num);
		fprintf(fp , "password=\"%s\"\n" , pass);
	}
}

int Build_script()
{
	//if (L!=NULL) lua_close(L);
	L=lua_open();
	luaL_openlibs(L);
	
	lua_pushcfunction(L, lua_say_qun);
	lua_setglobal(L, "say_qun");

	lua_pushcfunction(L, lua_say_buddy);
	lua_setglobal(L, "say_buddy");

	lua_pushcfunction(L, lua_to_gb_force);
	lua_setglobal(L, "to_gb");
	
	lua_pushcfunction(L, lua_charcolore);
	lua_setglobal(L, "charcolore");

	lua_pushcfunction(L, get_script);
	lua_setglobal(L, "get_scriptfolder");

	lua_pushcfunction(L, lua_loadlib);
	lua_setglobal(L, "loadlib");

	lua_pushcfunction(L, lua_LoadAddin);
	lua_setglobal(L, "loadaddin");

	//MSG("Functions push top.\n");
	
	mchdir(lua);
	if (luaL_dofile(L,".\\main.lua") != 0){
		MSG(lua_tostring(L, -1));
		setcolor( CCOL_RED );
		MSG(_TEXT("\n脚本有误请检查\n"));
		setcolor( CCOL_NONE );
		mchdir(root);
		return 0;
	}
	lua_getglobal(L, "startup");
	if (lua_pcall_to_dir(L, 0, 0, 0) != 0){
		MSG(lua_tostring(L, -1));
	}

	if (script_test_run()!=0){
		charcolor(CCOL_RED);
		MSG(lua_tostring(L, -1));
		MSG(_TEXT("\nmain.lua正确，但插件脚本"));
		charcolor(CCOL_NONE);
		MSG(_TEXT("很有可能"));
		charcolor(CCOL_RED);
		MSG(_TEXT("存在错误，请自行决定是否仍然使用新的代码。"));
		charcolor(CCOL_NONE);
		MSG(_TEXT("(按任意键继续...)\n"));
		getch();
	}
	
	mchdir(root);
	return 1;
}

int script_test_run()
{
	mchroot();
	MSG(_TEXT("尝试调用\"main\"函数..."));
	lua_getglobal(L, "main");
	lua_pushstring(L,"{Test To Run Once}");
	lua_pushstring(L,"{Test To Run Once}");
	lua_pushstring(L,"{Test To Run Once}");
	lua_pushnumber(L,100000);
	lua_pushstring(L,"{Test To Run Once}");
	lua_pushnumber(L,100000);

	if (lua_pcall_to_dir(L, 6, 0, 0) != 0){//main 函数有错
		charcolor(CCOL_RED);
		MSG(_TEXT("错误\n"));
		charcolor(CCOL_NONE);
		return 1;
	}else{//main 函数正确
		charcolor(CCOL_GREEN);
		MSG(_TEXT("正确\n"));
		charcolor(CCOL_NONE);
		MSG(_TEXT("尝试调用\"main_buddy\"函数..."));
		lua_getglobal(L, "main_buddy");
		lua_pushstring(L,"{Test To Run Once}");
		lua_pushstring(L,"{Test To Run Once}");
		lua_pushstring(L,"{Test To Run Once}");
		lua_pushnumber(L,10000);

		if (lua_pcall_to_dir(L, 4, 0, 0) != 0){//main_buddy 函数有错
			charcolor(CCOL_RED);
			MSG(_TEXT("错误\n"));
			charcolor(CCOL_NONE);
			return 2;
		}else{//main_buddy 函数正确
			charcolor(CCOL_GREEN);
			MSG(_TEXT("正确\n"));
			charcolor(CCOL_NONE);
			return 0;
		}
	}
}

int ReBuild_script()
{
	MSG(_TEXT( "\n\n重新读取lua代码\n"));
	//if (tL!=NULL) lua_close(tL);
	tL=lua_open();
	luaL_openlibs(tL);
	while (1)
	{
		mchdir(lua);
		if (luaL_dofile(tL,"main.lua") != 0){
			MSG(lua_tostring(tL, -1));
			charcolor( CCOL_RED );
			MSG(_TEXT("\n脚本有误请检查\n"));
			charcolor( CCOL_NONE );
			PAUSE
			continue;
		}
		lua_close(tL);
		
		lua_getglobal(L, "startup");
		if (lua_pcall_to_dir(L, 0, 0, 0) != 0){
			MSG(lua_tostring(L, -1));
		}
		if (script_test_run()!=0){
			charcolor(CCOL_RED);
			MSG(lua_tostring(L, -1));
			MSG(_TEXT("\nmain.lua正确，但插件脚本"));
			charcolor(CCOL_NONE);
			MSG(_TEXT("很有可能"));
			charcolor(CCOL_RED);
			MSG(_TEXT("存在错误，请自行决定是否仍然使用新的代码。"));
			charcolor(CCOL_NONE);
			MSG(_TEXT("(按任意键继续...)\n"));
			getch();
		}

		clear_screen();
		Build_script();

		charcolor( CCOL_GREEN );
		MSG(_TEXT("新代码验证完毕\n\n"),tL);
		charcolor( CCOL_NONE );

		MSG( _TEXT(help_msg) );

		RESET_INPUT
		break;
	}
	//lua_close(tL);
}

#ifndef __WIN32__
int read_password(char   *lineptr )
{

	struct   termios   old,   new;
	int   nread;
	/*   Turn   echoing   off   and   fail   if   we   can't.   */
	if   (tcgetattr   (fileno   (stdout),   &old)   !=   0)
		return   -1;
	new   =   old;
	new.c_lflag   &=   ~ECHO;
	if   (tcsetattr   (fileno   (stdout),   TCSAFLUSH,   &new)   !=   0)
		return   -1;
	/*   Read   the   password.   */
	nread   =   scanf   ("%31s", lineptr);
	/*   Restore   terminal.   */
	(void)   tcsetattr   (fileno   (stdout),   TCSAFLUSH,   &old);
	return   nread;
}
#endif

void init1stRun(){
	mkdir("settings");
	mkdir("verify");
	mkdir("log");
	mkdir("data");
}

int main(int argc, char** argv)
{
	//MSG("Program Started.\n");
	init1stRun();

	srand(time(NULL));
	//init data
	config_init();
	qqsocket_init();
	//no color?
	if( config_readint( g_conf, "NoColor" ) )
		no_color = 1;
	NEW( qun_buf, QUN_BUF_SIZE );
	NEW( buddy_buf, BUDDY_BUF_SIZE );
	NEW( print_buf, PRINT_BUF_SIZE );
	NEW( qq, sizeof(qqclient) );
	if( !qun_buf || !buddy_buf || !print_buf || !qq )
	{
		MSG("no enough memory.");
		return -1;
	}

	//MSG("Memory Allocated.\n");

	Build_script_r();
	while (1){
		if (Build_script()!=0) break;
		PAUSE
	}

	//MSG("Script Loaded.\n");
	//-----------------

DO_LOGIN:
	if( argc<3 )
	{
		qqclient_create( qq, uid, password );
		qq->mode = QQ_ONLINE;
		qqclient_login( qq );
	}
	else
	{
		//check if failed here...
		qqclient_create( qq, atoi(argv[1]), argv[2] );
		if( argc > 3 )
			qq->mode = atoi(argv[3])!=0 ? QQ_HIDDEN : QQ_ONLINE;
		qqclient_login( qq );
		argc = 1;
	}

	MSG(_TEXT("登陆中...\n"));
	for( ; qq->process != P_LOGIN;
			qqclient_wait( qq, 1 ) /*wait one second*/ )
	{
		switch( qq->process )
		{
		case P_LOGGING:
			continue;
		case P_VERIFYING:
#ifdef __WIN32__
				;char verdi[512];
				sprintf(verdi,"%s\\", qq->verify_dir );
				ShellExecute(NULL, "open", verdi, NULL, NULL, SW_SHOWNOACTIVATE);
#endif
			MSG(_TEXT("请输入验证码（验证码目录下）: "));
			scanf( "%s", input );
			qqclient_verify( qq, input );
			break;
		case P_ERROR:
			MSG(_TEXT("网络错误.\n"));
			qqclient_logout( qq );
			qqclient_cleanup( qq );
			goto DO_LOGIN;
		case P_DENIED:
			MSG(_TEXT("您的QQ需要激活(http://jihuo.qq.com).\n"));
#ifdef __WIN32__
			ShellExecute(NULL,"open","http://jihuo.qq.com/",NULL,NULL,SW_SHOWNORMAL);
#endif
			qqclient_logout( qq );
			qqclient_cleanup( qq );
			PAUSE
			goto DO_LOGIN;
		case P_WRONGPASS:
			MSG(_TEXT("您的密码错误.\n"));
			qqclient_logout( qq );
			qqclient_cleanup( qq );
			FILE *fp=fopen("settings\\qq.lua","wt");
			rebuild_qqRember(fp);
			fclose(fp);
			goto DO_LOGIN;
		default:
			MSG(_TEXT("未知错误.\n"));
		}
	}
	/* Success */

	load_last_cmd();

	MSG( _TEXT(help_msg) );

	messageLoop();


end:
	qqclient_logout( qq );
	qqclient_cleanup( qq );
	config_end();
	DEL( qq );
	MSG(_TEXT("离开.\n"));
	DEL( qun_buf );
	DEL( buddy_buf );
	DEL( print_buf );
	setcolor( CCOL_NONE );
	lua_close(L);
	memory_end();
	return 0;
}

void c_enter_qun(char arg[]){
	int n = atoi( arg );
	if( n < 0xFFFF ){
	char *p;
	p = skip_line( qun_buf, n-1 );
		if( p )
		{
			sscanf( p, "%u%u", &n, &qun_int_uid );
			sprintf( print_buf, "您在 %s 群中\n", myqq_get_qun_name( qq, qun_int_uid) );
			MSG( _TEXT(print_buf) );
			enter = 1;
			save_last_cmd("enter",arg);
			return;
		}
	}else{
		qun_int_uid = n;
		sprintf( print_buf, "您在 %s 群中\n", myqq_get_qun_name( qq, qun_int_uid) );
		MSG( _TEXT(print_buf) );
		enter = 1;
		save_last_cmd("e",arg);
		return;
	}
	sprintf( print_buf, "enter: %s 没有找到.\n", arg );
	MSG( _TEXT(print_buf) );
	return;

}

void c_to_buddy(char arg[]){
	if( enter )
	{
		MSG(_TEXT("您在一个群中, 你可以和任何人谈话.\n"));
		return;
	}
	int n = atoi( arg );
	if( n < 0xFFFF )
	{
		char *p;
		p = skip_line( buddy_buf, n-1 );
		if( p )
		{
			sscanf( p, "%u%u", &n, &to_uid );
			sprintf( print_buf, "您将和 %s 进行谈话\n", myqq_get_buddy_name(qq, to_uid) );
			MSG( _TEXT(print_buf) );
			save_last_cmd("t",arg);
			return;
		}
	}
	else
	{
		to_uid = n;
		sprintf( print_buf, "您将和 %s 进行谈话\n", myqq_get_buddy_name(qq, to_uid) );
		MSG( _TEXT(print_buf) );
		save_last_cmd("to",arg);
		return;
	}
	sprintf( print_buf, "to: %s 没有找到.\n", arg );
	MSG( _TEXT(print_buf) );
	return;
}

static int messageLoop(){
	mchroot();
	int cmdid, lastcmd=-1, len;
	char cmd[16], arg[1008];
	while( qq->process != P_INIT )
	{
		RESET_INPUT
		len = getline( input, 1023 );
		if( len < 1 ) continue;
		char* sp = strchr( input, ' ' );
		if( sp )
		{
			*sp = '\0';
			strncpy( cmd, input, 16-1 );
			strncpy( arg, sp+1, 1008-1 );
			*sp = ' ';
		}
		else
		{
			strncpy( cmd, input, 16-1 );
			arg[0] = '\0';
		}
		need_reset = 1;
		for( cmdid=0; cmdid<sizeof(commands)/16; cmdid++ )
			if( strcmp( commands[cmdid], cmd )==0 )
				break;
SELECT_CMD:
		switch( cmdid )
		{
		case CMD_TO:
			c_to_buddy(arg);
			break;
		case CMD_SAY:
		{
			if( enter )
			{
#ifdef	__WIN32__
				if( myqq_send_im_to_qun( qq, qun_int_uid, to_utf8(arg), 1 ) < 0 )
#else
				if( myqq_send_im_to_qun( qq, qun_int_uid, arg, 1 ) < 0 )
#endif
				{
					MSG(_TEXT("超时: 您的消息发送失败.\n"));
				}
			}
			else
			{
				if( to_uid == 0 )
				{
					MSG(_TEXT("say: 和谁谈话?必须先使用enter命令或to命令！\n"));
					break;
				}
#ifdef	__WIN32__
				if( myqq_send_im_to_buddy( qq, to_uid, to_utf8(arg), 1 ) < 0 )
#else
				if( myqq_send_im_to_buddy( qq, to_uid, arg, 1 ) < 0 )
#endif
				{
					MSG(_TEXT("超时: 您的消息发送失败.\n"));
				}
			}
			break;
		}
		case CMD_PIC:
		/*{
			if( enter )
			{
#ifdef	__WIN32__
				if( myqq_send_im_to_qun( qq, qun_int_uid, to_utf8(arg), 1 ) < 0 )
#else
				if( myqq_send_im_to_qun( qq, qun_int_uid, arg, 1 ) < 0 )
#endif
				{
					MSG(_TEXT("超时: 您的图片发送失败.\n"));
				}
			}else{
				MSG(_TEXT("图片只能向群中发送.\n"));
			}
		}*/
		case CMD_EXIT:
			return 0;
		case CMD_HELP:
			MSG( _TEXT(help_msg) );
			break;
		case CMD_CLS:
			clear_screen();
		case CMD_STATUS:
			if( strcmp( arg, "away") == 0 )
				qqclient_change_status( qq, QQ_AWAY );
			else if( strcmp( arg, "online") == 0 )
				qqclient_change_status( qq, QQ_ONLINE );
			else if( strcmp( arg, "hidden") == 0 )
				qqclient_change_status( qq, QQ_HIDDEN );
			else if( strcmp( arg, "killme") == 0 )
				qqclient_change_status( qq, QQ_KILLME );
			else if( strcmp( arg, "busy") == 0 )
				qqclient_change_status( qq, QQ_BUSY );
			else
			{
				MSG(_TEXT("未知状态\n") );
			}
			break;
		case CMD_ENTER:
			c_enter_qun(arg);
			break;

		case CMD_LEAVE:
			if( !enter )
			{
				MSG(_TEXT("您没有进入群.\n"));
				break;
			}
			enter = 0;
			sprintf( print_buf, "离开 %s. 您将和 %s 进行谈话\n",
					 myqq_get_qun_name( qq, qun_int_uid ), myqq_get_buddy_name( qq, to_uid ) );
			MSG( _TEXT(print_buf) );
			break;
		case CMD_QUN:
		{
			myqq_get_qun_list( qq, qun_buf, QUN_BUF_SIZE );
			MSG( _TEXT( qun_buf ) );
			break;
		}
		case CMD_UPDATE:
			qun_update_all( qq );
			buddy_update_list( qq );
			group_update_list( qq );
			MSG(_TEXT("更新中...\n"));
			if( qqclient_wait( qq, 20 )<0 )
			{
				MSG(_TEXT("更新超时.\n"));
			}
			break;
		case CMD_INFO:
		{
			if( !enter )
			{
				if( to_uid==0 )
				{
					MSG(_TEXT("请先选择一个好友.\n"));
				}
				else
				{
					char* buf = (char*)malloc(1024*4);	//4kb enough!
					//update single buddy info
					buddy_update_info( qq, buddy_get( qq, to_uid, 0 ) );
					if( qqclient_wait( qq, 10 ) < 0 )
					{
						MSG( _TEXT("获取好友详细资料失败。\n") );
					}
					if( myqq_get_buddy_info( qq, to_uid, buf, 1024*4 ) < 0 )
					{
						sprintf( print_buf, "获取 %s 的信息失败\n", myqq_get_buddy_name( qq, to_uid ) );
						MSG( _TEXT(print_buf) );
					}
					else
					{
						MSG( _TEXT( buf ) );
					}
					free(buf);
				}
			}
			else
			{
				char* buf = (char*)malloc(1024*4);	//4kb enough!
				if( myqq_get_qun_info( qq, qun_int_uid, buf, 1024*4 ) < 0 )
				{
					sprintf( print_buf, "获取 %s 的信息失败\n", myqq_get_qun_name( qq, qun_int_uid ) );
					MSG( _TEXT(print_buf) );
				}
				else
				{
					MSG( _TEXT( buf ) );
				}
				free(buf);
			}
			break;
		}
		case CMD_VIEW:
			if( enter )
			{
				myqq_get_qun_member_list( qq, qun_int_uid, buddy_buf,
										  BUDDY_BUF_SIZE, 0 );
				MSG( _TEXT( buddy_buf ) );
			}
			else
			{
				myqq_get_buddy_list( qq, buddy_buf, BUDDY_BUF_SIZE, 0 );
				MSG( _TEXT( buddy_buf ) );
			}
			break;
		case CMD_WHO:
			if( enter )
			{
				myqq_get_qun_member_list( qq, qun_int_uid, buddy_buf,
										  QUN_BUF_SIZE, 1 );
				MSG( _TEXT( buddy_buf ) );
			}
			else
			{
				myqq_get_buddy_list( qq, buddy_buf, QUN_BUF_SIZE, 1 );
				MSG( _TEXT( buddy_buf ) );
			}
			break;
		case CMD_CHANGE:
			qqclient_logout( qq );
			qqclient_cleanup( qq );
			main( 0, NULL );
			return 0;
		case CMD_VERIFY:
			qqclient_verify( qq, arg );
			break;
		case CMD_ADD:
		{
			sprintf( print_buf, "添加[%d]的附言（默认空）：", atoi(arg) );
			MSG( _TEXT(print_buf) );
			getline( input, 50 );
			qqclient_add( qq, atoi(arg), input );
			break;
		}
		case CMD_DEL:
			qqclient_del( qq, atoi(arg) );
			break;
		case CMD_RRLOAD:
			ReBuild_script();
			break;
		case CMD_SET_FONT_NAME:
			;char tmpout[50];
			strcpy(tmpout , "字体变更为 : ");
			strcat(tmpout,set_font_name(arg));
			MSG( _TEXT(tmpout) );
			MSG( "\n" );
			ZeroMemory( tmpout, 50 ) ;
			break;
		case CMD_SET_FONT_SIZE:
			MSG( _TEXT("字号变更为 : %d\n"),set_font_size(atoi(arg)) );
			break;
		case CMD_DBG:
			debug_setting_switch_by_str(arg);
			break;
		default:
			//use it as the last cmd's argument
			if( lastcmd && *input )
			{
				cmdid = lastcmd;
				strncpy( arg, input, 1008-1 );
				*input = 0;
				goto SELECT_CMD;
			}else if( !lastcmd ){
				MSG(_TEXT("未知命令\n"));
			}
			break;
		}
		lastcmd = cmdid;
	}

}

void save_last_cmd(char cmd[],char arg[]){
	FILE *fp;
	if ((fp=fopen("settings\\pre.s","wt+"))==NULL)
	{
		MSG(_TEXT("\nCannot open settings file!\n"));
	}

	//MSG(_TEXT("Save setting\n"));

	fputs(cmd,fp);		//对人还是群

	fputs(" ",fp);

	fputs(arg,fp);		//号码

	fclose(fp);
	return;
}

int load_last_cmd(){
	FILE *fp;

	MSG(_TEXT("Read setting："));

	fp=fopen("settings\\pre.s","rt");
	if (fp==NULL)
	{
		MSG("No settings file..\n");
		return 0;
	}

	char cmd[33]="",what[2]="",to[30]="";
	fgets(cmd,64,fp);	//对人还是群

	char* sp = strchr( cmd, ' ' );
	if( sp ){
		*sp = '\0';
		strncpy( what, cmd, 1 );
		strncpy( to, sp+1, 29 );

		//MSG(_TEXT("%s %s \n"),what,to);

		if (strstr( what, "e" )) {

			c_enter_qun(to);
		}else if (strstr( what, "t" )) {
			c_to_buddy(to);
		}else{
			MSG(_TEXT("Not Available \n"));
		}
	}else{
		MSG(_TEXT("Empty \n"));
	}
	fclose(fp);

	return 1;
}


